﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlServerCe;
using TekaMUD.Engine.Blocks;
using TekaMUD.Engine.Framework;
using System.Data;

namespace TekaMUD.Engine.Persistence
{
	public class LandStorage
	{
		public static void LoadContinents(SqlCeConnection conn)
		{
			SqlCeCommand cmd = new SqlCeCommand("select * from Continent", conn);

			using (IDataReader r = cmd.ExecuteReader())
			{
				while (r.Read())
				{
					try
					{
						Continent c = new Continent(r["Name"] as String, (int)r["X_Size"], (int)r["Y_Size"]);
						Logger.LogInfo("Adding continent: " + c.Name);

						int? weatherID = (int)r["id_weather"];

						if (weatherID.HasValue)
						{
							Logger.LogInfo("Loading weather data");

							c.Environment = WeatherStorage.LoadEnvironmentData(weatherID.Value, conn);
						}
						else
							c.Environment = new EnvData();

                        EntityManager.RegisterInstance(c);

						c.AddSector(LoadSectors((int)r["id"], conn));

						World.Current.AddContinent(c);
					}
					catch (Exception ex)
					{
						Logger.LogError("Failed load continent: " + ex.Message);
						throw ex;
					}
				}
			}

			// Load connections only after all rooms in all sectors are loaded.
			LoadConnections(conn);
		}

		private static List<Sector> LoadSectors(int id_continent, SqlCeConnection conn)
		{
			List<Sector> ret = new List<Sector>();

			SqlCeCommand cmd = new SqlCeCommand("select * from sector where id_continent = " + id_continent, conn);

			using (IDataReader r = cmd.ExecuteReader())
			{
				while (r.Read())
				{
					try
					{
						Sector s = new Sector() { Name = r["name"] as string, Flags = (EnumRoomFlags)r["RoomFlags"] };

						// Load all rooms
						Dictionary<Guid, Room> RoomsDictionary = LoadRooms(conn, (int)r["ID"]);

						foreach (Room room in RoomsDictionary.Values)
							s.AddRoom(room);

						Guid? startRoomGuid = r.IsDBNull(r.GetOrdinal("StartRoomGuid")) ? (Guid?)null : r.GetGuid(r.GetOrdinal("StartRoomGuid"));

						if (startRoomGuid.HasValue && RoomsDictionary.ContainsKey(startRoomGuid.Value))
							s.StartRoom = RoomsDictionary[startRoomGuid.Value];

                        EntityManager.RegisterInstance(s);
						ret.Add(s);
					}
					catch (Exception ex)
					{
						Logger.LogError("Failed load sector: " + ex.Message);
						throw ex;
					}
				}
			}

			return ret;
		}

		private static void UpdateLand(SqlCeConnection conn)
		{
		}

		private static Dictionary<Guid, Room> LoadRooms(SqlCeConnection conn, int sectorID)
		{
			Dictionary<Guid, Room> RoomsDictionary = new Dictionary<Guid, Room>();

			SqlCeCommand cmd = new SqlCeCommand("select * from room where id_sector = " + sectorID, conn);

			using (IDataReader r = cmd.ExecuteReader())
			{
				while (r.Read())
				{
					try
					{
						Room room = new Room(r["name"] as string)
						{
							UID = (Guid)r["Guid"],
							ExitMessages = Storage.FixStringSeparations(r["ExitMessage"] as string),
							EnterMessage = Storage.FixStringSeparations(r["EnterMessage"] as string),
							ExamineDescription = Storage.FixStringSeparations(r["ExamineDescription"] as string),
							Flags = (EnumRoomFlags)r["RoomFlags"],
							LookDescription = Storage.FixStringSeparations(r["LookDescription"] as string)

						};

                        EntityManager.RegisterInstance(room);
						RoomsDictionary.Add(room.UID, room);
					}
					catch (Exception ex)
					{
						Logger.LogError("Failed load sector: " + ex.Message);
					}
				}
			}

			return RoomsDictionary;
		}

		private static void LoadConnections(SqlCeConnection conn)
		{
			SqlCeCommand cmd = new SqlCeCommand("select * from RoomConnection", conn);

			using (IDataReader r = cmd.ExecuteReader())
			{
				while (r.Read())
				{
					try
					{
						EnumDirectionType Direction = (EnumDirectionType)r["DirectionEnum"];
						EnumDirectionType? RevDirec = r.IsDBNull(r.GetOrdinal("ReverseDirectionEnum")) ? (EnumDirectionType?)null : (EnumDirectionType)r["ReverseDirectionEnum"];
						Room start = EntityManager.GetRoomByID((Guid)r["StartRoom"]);
						Room end = EntityManager.GetRoomByID((Guid)r["EndRoom"]);
						int? doorId = r.IsDBNull(r.GetOrdinal("ID_Door")) ? null : (int?)r["ID_Door"];



						if (doorId.HasValue)
						{
							Door d = LoadDoor(doorId.Value, conn);
							start.AddConnection(end, Direction, RevDirec, d);
						}
						else
						{
							start.AddConnection(end, Direction, RevDirec, null);
						}

					}
					catch (Exception ex)
					{
						Logger.LogError("Failed load room connection: " + ex.Message);
					}
				}
			}
		}

		private static Door LoadDoor(int doorID, SqlCeConnection conn)
		{
			SqlCeCommand cmd = new SqlCeCommand("select * from door d inner join gameobject go on go.id = d.id_gameobject where d.id_gameobject = " + doorID, conn);

			using (IDataReader r = cmd.ExecuteReader())
			{
				if(r.Read())
				{
					Door d = new Door()
					{
						UID = (Guid)r["Guid"],
						ExamineDescription = Storage.FixStringSeparations(r["ExamineDescription"] as string),
						LookDescription = Storage.FixStringSeparations(r["LookDescription"] as string),
						AutoClose = (bool) r["AutoClose"],
						Opened = (bool) r["Opened"]
					};

					string adjs = (string)r["AdjectivesArray"];

					if(adjs != null)
						foreach(string adj in adjs.Split(','))
							d.AddAdjective(adj);

					string keys = (string)r["AllowedKeysArray"];

					if (keys != null)
						foreach (string keyGuid in keys.Split(','))
							d.AssignKey(new Guid(keyGuid));

                    EntityManager.RegisterInstance(d);
					return d;
				}

				throw new SystemException("Door not found");
			}
		}
	}
}